package com.witsight.hibernate.config;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManagerFactory;

import org.aspectj.lang.annotation.Aspect;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**   
 * 说明：事物切面拦截器
 * @Title: TxAdviceInterceptor.java 
 * @Package com.witsight.hibernate.config 
 * @See: {@link #TxAdviceInterceptor()}
 * 		 {@value #TX_METHOD_NAMES}
 * Copyright: Copyright (c) 2017
 * Company:sany huax witsight team by product
 * @author: fuyp  
 * @date: 2017年9月18日 下午5:45:19 
 * @version: V1.0
 *
 */
@Aspect
@Configuration
public class TxAdviceInterceptor {
	private static final Logger log = LoggerFactory.getLogger(TxAdviceInterceptor.class);
	private static final Map<String,Boolean> TX_METHOD_NAMES = new HashMap<>();
    private static final int TX_METHOD_TIMEOUT = 3;
    // 事物服务类规则com.witsight.demo.service / com.witsight.demo.service.impl
    private static final String AOP_POINTCUT_EXPRESSION = "execution(* com..*.service..*.*(..))";
    
    /**
     * 事物规则配置
     */
    static {
    	// 增删改
    	TX_METHOD_NAMES.put("save*", false);
    	TX_METHOD_NAMES.put("create*", false);
    	TX_METHOD_NAMES.put("add*", false);
    	TX_METHOD_NAMES.put("delete*", false);
    	TX_METHOD_NAMES.put("remove*", false);
    	TX_METHOD_NAMES.put("update*", false);
    	TX_METHOD_NAMES.put("upload*", false);
    	TX_METHOD_NAMES.put("gen*", false);
    	// 读
    	TX_METHOD_NAMES.put("get*", true);
    	TX_METHOD_NAMES.put("count*", true);
    	TX_METHOD_NAMES.put("find*", true);
    	TX_METHOD_NAMES.put("list*", true);
    	TX_METHOD_NAMES.put("search*", true);
    	TX_METHOD_NAMES.put("*", true);
    }
    // 事物管理类
    @Autowired
    private JpaTransactionManager customTransactionManager;
    /**
     * 
     * 说明：事物切面
     * @Title: txAdvice
     * @See: {@link TransactionInterceptor}
     * @author fuyp
     * @return TransactionInterceptor
     * @date: 2017年6月16日 下午12:52:54
     */
//    @Bean(name="transactionInterceptor")
    public TransactionInterceptor txAdvice() {
		NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
		for (String key : TX_METHOD_NAMES.keySet()) {
			RuleBasedTransactionAttribute transactionAttribute = new RuleBasedTransactionAttribute();
			transactionAttribute.setName(key);
			transactionAttribute.setReadOnly(TX_METHOD_NAMES.get(key));
			// transactionAttribute.setTimeout(TX_METHOD_TIMEOUT);
			if (TX_METHOD_NAMES.get(key)) { // 只读
				transactionAttribute.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
				transactionAttribute.setReadOnly(true);
				if (log.isDebugEnabled()) {
					log.debug("Transaction readOnly rule, key:{}", key);
				}
			} else {// 事物提交
				transactionAttribute.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
				transactionAttribute.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
				if (log.isDebugEnabled()) {
					log.debug("Transaction write rule, key:{}", key);
				}
			}
			source.addTransactionalMethod(key, transactionAttribute);
		}

		TransactionInterceptor txAdvice = new TransactionInterceptor();
		txAdvice.setTransactionManager(customTransactionManager);
		txAdvice.setTransactionAttributeSource(source);
		return txAdvice;
    }
    
    /**
     * 
     * 说明：切面事物
     * @Title: txAdviceAdvisor
     * @See: {@link DefaultPointcutAdvisor}
     * @author fuyp
     * @return Advisor
     * @date: 2017年6月16日 下午12:52:10
     */
    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, txAdvice());
        advisor.setOrder(com.witsight.platform.Constants.TX_ORDER);
        return advisor;
    }
}
